package com.gmscosmo.janus.handler;

import com.alibaba.fastjson.JSONObject;
import com.gmscosmo.janus.util.JanusLogUtil;
import com.gmscosmo.model.RtpForwardData;
import com.gmscosmo.model.*;
import com.gmscosmo.request.*;
import com.gmscosmo.janus.util.CommonUtils;
import com.gmscosmo.common.JanusNativeSignaling;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;


/**
 * ClassName: JanusVideoRoomRabbitMqEventHandler
 * Description:
 * Date: 2021/10/12 10:54
 *
 * @author stephen.qiu
 * @version 1.0
 */
@Component
public class JanusVideoRoomRabbitMqEventHandler extends JanusVideoRoomHandler {
    /**
     * 判断房间是否存在
     *
     * @param roomExistData
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public boolean roomExist(JSONObject roomExistData, int nodeId) throws Exception {
        JanusRequest roomExistRequest = new JanusRequest();
        roomExistRequest.setJanus(JanusNativeSignaling.MESSAGE);

        JanusRequestBody roomExistBody = new JanusRequestBody();
        roomExistBody.setRoom(Integer.valueOf(roomExistData.getString("room_id").split("\\|")[1]));
        roomExistBody.setRequest(JanusNativeSignaling.EXISTS);

        String transaction = CommonUtils.randomString(12);
        roomExistRequest.setTransaction(transaction);
        long session_id = roomExistData.getLong("session_id");
        long handle_id = roomExistData.getLong("handle_id");

        roomExistRequest.setSession_id(session_id);
        roomExistRequest.setHandle_id(handle_id);
        roomExistRequest.setBody(roomExistBody);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(roomExistRequest).toString(), nodeId).get();
        return response.getJSONObject("plugindata").getJSONObject("data").getBoolean("exists");
    }

    /**
     * 创建房间
     *
     * @param createRoomData
     * @param session_id
     * @param handle_id
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String createRoom(JSONObject createRoomData, long session_id, long handle_id, int nodeId) throws Exception {
        JanusRequest createRoomRequest = new JanusRequest();
        createRoomRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        createRoomRequest.setTransaction(transaction);
        createRoomRequest.setSession_id(session_id);
        createRoomRequest.setHandle_id(handle_id);

        CreateRoomBody createRoomBody = new CreateRoomBody();
        createRoomBody.setRequest(JanusNativeSignaling.CREATE);
        createRoomBody.setRoom(Integer.valueOf(createRoomData.getString("room_id").split("\\|")[1]));
        JSONObject createRoomDataBody = createRoomData.getJSONObject("body");
        createRoomBody.setPublishers(createRoomDataBody.getInteger("publishers"));
        createRoomBody.setPin(createRoomDataBody.getString("pin"));
        createRoomBody.setIs_public(createRoomDataBody.getBoolean("is_public"));
        createRoomBody.setNotify_joining(true);
//        createRoomBody.setFir_freq(1);
//        createRoomBody.setVideocodec(VideoCodec.VP8);

        createRoomRequest.setBody(createRoomBody);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(createRoomRequest).toString(), nodeId).get();
        response.put("handle_id", handle_id);
        return response.toString();
    }

    /**
     * 加入房间
     *
     * @param joinData
     * @param type
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String join(JSONObject joinData, String type, int nodeId) throws Exception {
        JanusRequest joinRequest = new JanusRequest();
        joinRequest.setJanus(JanusNativeSignaling.MESSAGE);

        JoinBody joinBody = new JoinBody();
        JSONObject joinDataBody = joinData.getJSONObject("body");
        joinBody.setPtype(type);
        joinBody.setRoom(Integer.valueOf(joinData.getString("room_id").split("\\|")[1]));
        joinBody.setRequest(JanusNativeSignaling.JOIN);
        joinBody.setPin(joinDataBody.getString("pin"));
        String transaction = CommonUtils.randomString(12);
        joinRequest.setTransaction(transaction);
        long session_id = joinData.getLong("session_id");
        long handle_id = joinData.getLong("handle_id");
        if ("publisher".equals(type)) {
            joinBody.setDisplay(joinData.getString("user_id"));
            joinBody.setId(joinDataBody.getLong("publisher_id"));
        } else if ("subscriber".equals(type)) {
            joinBody.setFeed(joinDataBody.getLong("feed"));
        }
        joinRequest.setSession_id(session_id);
        joinRequest.setHandle_id(handle_id);
        joinRequest.setBody(joinBody);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(joinRequest).toString(), nodeId).get();
        response.put("handle_id", handle_id);
        return response.toString();
    }

    /**
     * 发送offer
     *
     * @param offerDate
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String sendOffer(JSONObject offerDate, int nodeId) throws Exception {
        offerDate = offerDate.getJSONObject("body");
        long session_id = offerDate.getLong("session_id");
        long handle_id = offerDate.getLong("handle_id");
        JSONObject offer_body = offerDate.getJSONObject("body");
        JSONObject jsepData = offerDate.getJSONObject("jsep");
        Jsep jsep = new Jsep();
        jsep.setSdp(jsepData.getString("sdp"));
        jsep.setType(jsepData.getString("type"));

        JanusRequest offerRequest = new JanusRequest();
        offerRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        offerRequest.setTransaction(transaction);
        offerRequest.setJsep(jsep);

        ConfigureBody configureBody = new ConfigureBody();
        configureBody.setRequest(JanusNativeSignaling.CONFIGURE);
        configureBody.setAudio(offer_body.getBoolean("audio"));
        configureBody.setVideo(offer_body.getBoolean("video"));
        configureBody.setPin(offer_body.getInteger("pin"));
        offerRequest.setBody(configureBody);
        offerRequest.setSession_id(session_id);
        offerRequest.setHandle_id(handle_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(offerRequest).toString(), nodeId).get();
        return response.toString();

    }

    /**
     * 发送候选者
     *
     * @param candidateDate
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String sendCandidate(JSONObject candidateDate, int nodeId) throws Exception {
        candidateDate = candidateDate.getJSONObject("body");
        String candidate = candidateDate.getString("candidate");
        long session_id = candidateDate.getLong("session_id");
        long handle_id = candidateDate.getLong("handle_id");

        JanusRequest candidateRequest = new JanusRequest();
        candidateRequest.setJanus(JanusNativeSignaling.TRICKLE);
        String transaction = CommonUtils.randomString(12);
        candidateRequest.setTransaction(transaction);
        candidateRequest.setCandidate(candidate);
        candidateRequest.setSession_id(session_id);
        candidateRequest.setHandle_id(handle_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(candidateRequest).toString(), nodeId).get();
        return response.toString();
    }

    /**
     * 保持活跃
     *
     * @param keepaliveData
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String keepalive(JSONObject keepaliveData, int nodeId) throws Exception {
        JanusRequest keepaliveRequest = new JanusRequest();
        keepaliveRequest.setJanus(JanusNativeSignaling.KEEP_A_LIVE);
        String transaction = CommonUtils.randomString(12);
        keepaliveRequest.setTransaction(transaction);
        long session_id = keepaliveData.getLong("session_id");
        keepaliveRequest.setSession_id(session_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(keepaliveRequest).toString(), nodeId).get();
        return response.toString();
    }

    /**
     * 离开房间
     *
     * @param leaveData
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String leave(JSONObject leaveData, int nodeId) throws Exception {
        JanusRequest leaveRequest = new JanusRequest();
        leaveRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        leaveRequest.setTransaction(transaction);
        long session_id = leaveData.getLong("session_id");

        JSONObject leaveBody = leaveData.getJSONObject("body");
        long handle_id = leaveBody.getLong("handle_id");
        boolean destroy = leaveBody.getBooleanValue("destroy");
        if (destroy) {
            destroy(leaveData, nodeId);
        }
        JanusRequestBody leaveRequestBody = new JanusRequestBody();
        leaveRequestBody.setRequest(JanusNativeSignaling.LEAVE);

        leaveRequest.setBody(leaveRequestBody);
        leaveRequest.setSession_id(session_id);
        leaveRequest.setHandle_id(handle_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(leaveRequest).toString(), nodeId).get();
        janusUtil.removeEventListener(session_id);
        return response.toString();
    }

    /**
     * 销毁房间
     *
     * @param destroyData
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String destroy(JSONObject destroyData, int nodeId) throws Exception {
        JanusRequest destroyRequest = new JanusRequest();
        destroyRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        destroyRequest.setTransaction(transaction);
        long session_id = destroyData.getLong("session_id");
        JSONObject leaveBody = destroyData.getJSONObject("body");
        long handle_id = leaveBody.getLong("handle_id");
        destroyRequest.setSession_id(session_id);
        destroyRequest.setHandle_id(handle_id);

        JanusRequestBody destroyRequestBody = new JanusRequestBody();
        destroyRequestBody.setRoom(Integer.valueOf(destroyData.getString("room_id").split("\\|")[1]));
        destroyRequestBody.setRequest(JanusNativeSignaling.DESTROY);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(destroyRequest).toString(), nodeId).get();
        return response.toString();
    }
    /**
     * 媒体协商
     *
     * @param configureData
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String configure(JSONObject configureData, int nodeId) throws Exception {
        configureData = configureData.getJSONObject("body");
        long session_id = configureData.getLong("session_id");
        long handle_id = configureData.getLong("handle_id");
        JanusRequest configureRequest = new JanusRequest();
        configureRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        configureRequest.setTransaction(transaction);

        ConfigureBody configureBody = new ConfigureBody();
        configureBody.setRequest(JanusNativeSignaling.CONFIGURE);
        configureBody.setSubstream(configureData.getInteger("substream"));
        configureBody.setTemporal(configureData.getInteger("temporal"));

        configureRequest.setBody(configureBody);
        configureRequest.setSession_id(session_id);
        configureRequest.setHandle_id(handle_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(configureRequest).toString(), nodeId).get();
        return response.toString();
    }

    public void handleRtpForwardRequest(String rtpForwardFrom, String rtpForwardTo, RtpForwardData data) throws Exception {
        Participant participant = janusUtil.getParticipantByUserId(rtpForwardFrom);
        long session_id = participant.getSession_id();
        long handle_id = participant.getHandle_id();
        long publisher_id = participant.getPublisher_id();
        int roomId = Integer.valueOf(janusUtil.getUserRoom(rtpForwardFrom));
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(data));
        jsonObject.put("session_id", session_id);
        jsonObject.put("handle_id", handle_id);
        jsonObject.put("publisher_id", publisher_id);
        jsonObject.put("room", roomId);
        jsonObject.put("rtpForwardTo", rtpForwardTo);
        rtpForward(jsonObject, rtpForwardFrom, janusUtil.getUserNode(rtpForwardFrom));
    }

    /**
     * 开始rtp转发
     *
     * @param rtpForwardData
     * @param rtpForwardFrom
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String rtpForward(JSONObject rtpForwardData, String rtpForwardFrom, int nodeId) throws Exception {
        long session_id = rtpForwardData.getLongValue("session_id");
        long handle_id = rtpForwardData.getLongValue("handle_id");
        JanusRequest configureRequest = new JanusRequest();
        configureRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        configureRequest.setTransaction(transaction);

        RtpForwardBody rtpForwardBody = new RtpForwardBody();
        rtpForwardBody.setRequest(JanusNativeSignaling.RTP_FORWARD);
        rtpForwardBody.setRoom(rtpForwardData.getInteger("room"));
        /**
         * 如果janus属于同于内外 则走内网转发
         */
        String myHost;
        String host;
        if (janusUtil.getNodeInfo(janusUtil.getUserNode(rtpForwardFrom)).getClusterId() == rtpForwardData.getInteger("clusterId")) {
            host = rtpForwardData.getString("interHost");
            myHost = janusUtil.getNodeInfo(janusUtil.getUserNode(rtpForwardFrom)).getInterHost();
        } else {
            host = rtpForwardData.getString("host");
            myHost = janusUtil.getNodeInfo(janusUtil.getUserNode(rtpForwardFrom)).getHost();
        }
        rtpForwardBody.setHost(host);
        rtpForwardBody.setVideo_port(rtpForwardData.getInteger("video_port"));
        rtpForwardBody.setAudio_port(rtpForwardData.getInteger("audio_port"));
        rtpForwardBody.setPublisher_id(rtpForwardData.getLong("publisher_id"));
        rtpForwardBody.setVideo_rtcp_port(rtpForwardData.getInteger("video_rtcp_port"));
        rtpForwardBody.setVideo_port_2(rtpForwardData.getInteger("video_port_2"));
        rtpForwardBody.setVideo_port_3(rtpForwardData.getInteger("video_port_3"));
        configureRequest.setBody(rtpForwardBody);
        configureRequest.setSession_id(session_id);
        configureRequest.setHandle_id(handle_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(configureRequest).toString(), nodeId).get();

        addProducer(
                session_id,
                handle_id,
                myHost,
                host,
                rtpForwardData.getInteger("id"),
                rtpForwardData.getInteger("room"),
                rtpForwardData.getInteger("publisher_id"),
                rtpForwardData.getInteger("audio_port"),
                rtpForwardData.getInteger("video_port"),
                rtpForwardData.getInteger("video_rtcp_port"),
                rtpForwardData.getString("rtpForwardTo"),
                rtpForwardFrom,
                response.getJSONObject("plugindata").getJSONObject("data").getJSONObject("rtp_stream").getLong("audio_stream_id"),
                response.getJSONObject("plugindata").getJSONObject("data").getJSONObject("rtp_stream").getLong("video_stream_id")
        );
        return response.toString();
    }

    /**
     * 停止所有rtp转发器
     * @param userId
     * @throws Exception
     */
    @Override
    public void stopMyRtpForward(String userId) throws Exception {
        if (!janusUtil.isProducersContains(userId)) {
            janusLogUtil.log("no RTP forwarder had to destroy.",this.getClass(), JanusLogUtil.INFO);
            return;
        }
        Participant participant = janusUtil.getParticipantByUserId(userId);
        long session_id = participant.getSession_id();
        long handle_id = participant.getHandle_id();
        int nodeId = participant.getNode();

        JanusRequest stopRtpForwardRequest = new JanusRequest();
        stopRtpForwardRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        stopRtpForwardRequest.setTransaction(transaction);
        stopRtpForwardRequest.setSession_id(session_id);
        stopRtpForwardRequest.setHandle_id(handle_id);
        RtpForwardBody rtpForwardBody = new RtpForwardBody();
        rtpForwardBody.setRequest(JanusNativeSignaling.STOP_RTP_FORWARD);
        List<Producer> producerList = janusUtil.getProducers(userId);
        for (Producer p : producerList) {
            rtpForwardBody.setRoom(p.getRoom());
            rtpForwardBody.setPublisher_id(p.getId());
            rtpForwardBody.setStream_id(p.getAudioStreamId());
            stopRtpForwardRequest.setBody(rtpForwardBody);
            janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(stopRtpForwardRequest).toString(), nodeId).get();
            rtpForwardBody.setStream_id(p.getVideoStreamId());
            stopRtpForwardRequest.setBody(rtpForwardBody);
            janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(stopRtpForwardRequest).toString(), nodeId).get();
        }
        janusUtil.removeProducers(userId);
    }

    /**
     * 停止rtp转发
     */
    @Override
    public void stopOtherRtpForward(String rtpForwardFrom, String rtpForwardTo) throws Exception {
        if (!janusUtil.isProducersContains(rtpForwardFrom)) {
            janusLogUtil.log("no RTP forwarder had to destroy.",this.getClass(),JanusLogUtil.INFO);
            return;
        }
        Participant participant = janusUtil.getParticipantByUserId(rtpForwardFrom);
        long session_id = participant.getSession_id();
        long handle_id = participant.getHandle_id();
        int nodeId = participant.getNode();

        JanusRequest stopRtpForwardRequest = new JanusRequest();
        stopRtpForwardRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        stopRtpForwardRequest.setTransaction(transaction);
        stopRtpForwardRequest.setSession_id(session_id);
        stopRtpForwardRequest.setHandle_id(handle_id);
        RtpForwardBody rtpForwardBody = new RtpForwardBody();
        rtpForwardBody.setRequest(JanusNativeSignaling.STOP_RTP_FORWARD);

        List<Producer> producerList = janusUtil.getProducers(rtpForwardFrom);
        List<Producer> producer = new ArrayList<>();
        for (Producer p : producerList) {
            if (p.getRtpForwardTo().equals(rtpForwardTo)) {
                producer.add(p);
                rtpForwardBody.setRoom(p.getRoom());
                rtpForwardBody.setPublisher_id(p.getId());
                rtpForwardBody.setStream_id(p.getAudioStreamId());
                stopRtpForwardRequest.setBody(rtpForwardBody);
                janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(stopRtpForwardRequest).toString(), nodeId).get();
                rtpForwardBody.setStream_id(p.getVideoStreamId());
                stopRtpForwardRequest.setBody(rtpForwardBody);
                janusAsyncSender.sendWithFuture(transaction, true, JSONObject.toJSON(stopRtpForwardRequest).toString(), nodeId).get();
            }
        }
        if (producer.size() != 0) {
            producerList.removeAll(producer);
            if (producerList.size() == 0) {
                janusUtil.removeProducers(rtpForwardFrom);
            } else {
                janusUtil.putProducers(rtpForwardFrom, producerList);
            }
        }
    }

    /**
     * 重新协商ice
     *
     * @param restartICEData
     * @param nodeId
     * @return
     * @throws Exception
     */
    @Override
    public String sendRestartICE(JSONObject restartICEData, int nodeId) throws Exception {
        restartICEData = restartICEData.getJSONObject("body");
        long session_id = restartICEData.getLong("session_id");
        long handle_id = restartICEData.getLong("handle_id");

        JanusRequest configureRequest = new JanusRequest();
        configureRequest.setJanus(JanusNativeSignaling.MESSAGE);
        String transaction = CommonUtils.randomString(12);
        configureRequest.setTransaction(transaction);

        ConfigureBody configureBody = new ConfigureBody();
        configureBody.setRequest(JanusNativeSignaling.CONFIGURE);
        configureBody.setRestart(true);

        configureRequest.setBody(configureBody);
        configureRequest.setSession_id(session_id);
        configureRequest.setHandle_id(handle_id);
        JSONObject response = janusAsyncSender.sendWithFuture(transaction, false, JSONObject.toJSON(configureRequest).toString(), nodeId).get();
        return response.toString();
    }
}
